﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.Mvc;
using Gola.VN.Scb.Web.Common;
using Gola.VN.Scb.Web.Common.Entities;
using Gola.VN.Scb.Web.Common.Models;
using Gola.VN.Scb.Web.Presentation.Helpers;
using Gola.VN.Scb.Web.Common;
using Gola.VN.Scb.Web.Presentation.Models;

namespace Gola.VN.Scb.Web.Presentation.Controllers
{
    public class ProductController : Controller
    {
        public const int pageSize = 15;

        // Product/DisplayByCategory/id/page/1
        // Product/DisplayByCategory/id
        public ActionResult DisplayByCategory(int id, int? page)
        {
            InitializeViewData();
            ViewData["OrderByData"] = CreateOrderByData();
            // ViewData["Navigation"] = CategoryService.GetNavigateData(id); //todo: replaced by ngocbv
            ViewData["Navigation"] = MainService.GetInstant().CategoryService.GetNavigateData(id);
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(id); //todo: replaced by ngocbv
            ViewData["CloudData"] = MainService.GetInstant().CategoryService.GetCloudCategory(id);
            var productModels = new UIProductModels();
            int pageIndex = page ?? 1;
            //get detail location foreach provider
            productModels.ProviderLocations = MainService.GetInstant().ProviderService.GetProviderAllLocations();

            // var products = ProductService.GetProductsByCategoryId(id); //todo: ngocbv
            var products = MainService.GetInstant().ProductService.GetProductsByCategoryId(id);
            productModels.Products = productModels.ProductsByCategory = new PaginatedList<ProductEntity>(products, pageIndex, pageSize);
            // ViewData["Title"] = Utilities.GetTitle(CategoryService.GetCategoryById(id).Name); //todo: replaced by ngocbv
            ViewData["Title"] = Utilities.GetTitle(MainService.GetInstant().CategoryService.GetCategoryById(id).Name);
            return View("ProductsGrid", productModels);
        }

        public ActionResult ProductDetail(int id, string keyword = "")
        {
            var uiProduct = new UIProductModels();
            // uiProduct.Product = ProductService.GetProduct(id); //todo: replaced by ngocbv
            uiProduct.Product = MainService.GetInstant().ProductService.GetProductById(id);
            // get left menu data
            // uiProduct.Categories = CategoryService.LeftPanelData; //todo: replace by ngocbv
            uiProduct.Categories = MainService.GetInstant().CategoryService.LeftPanelData;
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(uiProduct.Product.CategoryId); //todo: replaced by ngocbv
            ViewData["CloudData"] =
                MainService.GetInstant().CategoryService.GetCloudCategory(uiProduct.Product.CategoryId);
            // get product with same title
            var exclusiveProduct = new List<int>();
            exclusiveProduct.Add(id);
            // var productsOfAllProvider = ProductService.GetOthersProduct(uiProduct.Product.Title, exclusiveProduct, 1); //todo: ngocbv
            var productsOfAllProvider = MainService.GetInstant().ProductService.GetOthersProductByTitle(uiProduct.Product.Title, exclusiveProduct, 1);
            //them chinh san pham vao list
            productsOfAllProvider.Insert(0, uiProduct.Product);
            //Enable btn goto website
            productsOfAllProvider.ForEach(item => item.EnableGoToWebsite = true);
            uiProduct.Products = new PaginatedList<ProductEntity>(productsOfAllProvider, 1, pageSize);

            // get products that is similar the detail product
            var exclusiveOrtherPro = productsOfAllProvider.Select(q => q.Id).ToList();
            // uiProduct.ProductsByCategory = new PaginatedList<ProductEntity>(ProductService.GetOthersProduct(uiProduct.Product.CategoryId, exclusiveOrtherPro, 1), 1, pageSize); //todo: ngocbv
            uiProduct.ProductsByCategory = new PaginatedList<ProductEntity>(
                MainService.GetInstant().ProductService.GetOthersProductByCategoryId(
                uiProduct.Product.CategoryId, exclusiveOrtherPro, 1), 1, pageSize);

            ViewData["Title"] = Utilities.GetTitle(uiProduct.Product.Title);
            // ViewData["Navigation"] = CategoryService.GetNavigateData(uiProduct.Product.CategoryId); //todo: replaced by ngocbv
            ViewData["Navigation"] =
                MainService.GetInstant().CategoryService.GetNavigateData(uiProduct.Product.CategoryId);

            uiProduct.Product.LocationDetail = MainService.GetInstant().ProviderService.GetProvider(uiProduct.Product.ProductId);

            // update search history
            if (!string.IsNullOrEmpty(keyword))
                MainService.GetInstant().SearchHistoryService.UpdateSearchHistory(new SearchHistoryEntity
                                                             {
                                                                 Text = uiProduct.Product.Title,
                                                                 Link = uiProduct.Product.View
                                                             });
            //get detail location foreach provider
            uiProduct.ProviderLocations = MainService.GetInstant().ProviderService.GetProviderAllLocations();

            //Increase ViewCount of this products
            MainService.GetInstant().ProductService.UpdateProductViewCount(id);

            return View("ProductDetailInner", uiProduct);
        }

        public ActionResult GoToWebsite(int id, string provider, string keyword)
        {
            var uiProductModels = new UIProductModels();
            // uiProductModels.Product = ProductService.GetProduct(id);//todo: replaced by ngocbv
            uiProductModels.Product = MainService.GetInstant().ProductService.GetProductById(id);
            //get detail location
            uiProductModels.Product.LocationDetail = MainService.GetInstant().ProviderService.GetProvider(id);
            string content = GetWebContent(uiProductModels.Product.Link);
            // using for display product detail in database
            uiProductModels.Product.IsAlive = string.IsNullOrEmpty(content) ? false : true;
            //Get products that are in other provider
            // var productsInOtherProvider = ProductService.GetProductsByProductTitle(id, uiProductModels.Product.Title); //todo: ngocbv
            var productsInOtherProvider = MainService.GetInstant().ProductService.GetProductsByProductTitle(id, uiProductModels.Product.Title);
            uiProductModels.Products = productsInOtherProvider;
            return View("ProductDetail", uiProductModels);
        }

        public ActionResult ProductCompare(int id, int page = -1)
        {
            var productModels = new UIProductModels();
            int pageSize = Utilities.PageCount;

            // get product detail
            // productModels.Product = ProductService.GetProduct(id); //todo: replaced by id
            productModels.Product = MainService.GetInstant().ProductService.GetProductById(id);
            productModels.Product.LocationDetail = MainService.GetInstant().ProviderService.GetProvider(
                productModels.Product.ProviderId);

            page = (page < 2) ? 1 : page - 1;

            // get product with same title
            // productModels.Products = ProductService.GetProductsByProductTitle(id, productModels.Product.Title); //todo: ngocbv
            productModels.Products = MainService.GetInstant().ProductService.GetProductsByProductTitle(id, productModels.Product.Title);
            productModels.Products = Utilities.GetPageView(page, productModels.Products);

            // get relate product
            // productModels.ProductsByCategory = new PaginatedList<ProductEntity>(ProductService.GetProductsByCategoryId(productModels.Product.CategoryId), //todo: ngocbv
            productModels.ProductsByCategory = new PaginatedList<ProductEntity>(
                MainService.GetInstant().ProductService.GetProductsByCategoryId(productModels.Product.CategoryId), page, pageSize);

            //get detail location foreach provider
            productModels.ProviderLocations = MainService.GetInstant().ProviderService.GetProviderAllLocations();

            ViewData["Title"] = Utilities.GetTitle("");
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(productModels.Product.CategoryId); //todo: replaced by ngocbv
            ViewData["CloudData"] =
                MainService.GetInstant().CategoryService.GetCloudCategory(productModels.Product.CategoryId);
            return View("AddProductCompare", productModels);
        }

        public ActionResult Products(string keyword)
        {
            var productModels = new UIProductModels();

            if (!string.IsNullOrEmpty(keyword))
            {
                // productModels.Products = ProductService.GetProductsByTitle(keyword); //todo: ngocbv
                productModels.Products = MainService.GetInstant().ProductService.GetProductsByTitle(keyword);
                MainService.GetInstant().SearchHistoryService.UpdateSearchHistory(new SearchHistoryEntity { Text = keyword, Link = Utilities.GetProductsView(keyword) });//Todo: must change links value
            }
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(productModels.Product.CategoryId); //todo: replaced by ngocbv
            ViewData["CloudData"] =
                MainService.GetInstant().CategoryService.GetCloudCategory(productModels.Product.CategoryId);
            return View("Products", productModels);
        }

        public ActionResult DisplayCompare(string ids)
        {
            var proModel = new UIProductModels();
            //get detail location foreach provider
            proModel.ProviderLocations = MainService.GetInstant().ProviderService.GetProviderAllLocations();
            var proIds = new List<int>();
            if (!string.IsNullOrEmpty(ids))
            {
                string[] tempIds = ids.Split(new[] { '-' });
                foreach (string sid in tempIds)
                {
                    int tempId = 0;
                    if (int.TryParse(sid, out tempId)) proIds.Add(tempId);
                }
            }

            proModel.Products = new List<ProductEntity>();
            foreach (int id in proIds)
            {
                // ProductEntity product = ProductService.GetProduct(id); //todo: replaced by id
                ProductEntity product = MainService.GetInstant().ProductService.GetProductById(id);
                if (product != null)
                {
                    proModel.Products.Add(product);
                }
            }
            InitializeViewData();
            // ViewData["Navigation"] = CategoryService.GetNavigateData(proModel.Products[0].CategoryId); //todo: replaced by ngocbv
            ViewData["Navigation"] =
                MainService.GetInstant().CategoryService.GetNavigateData(proModel.Products[0].CategoryId);
            //Get page tile.
            // ViewData["Title"] = Utilities.GetTitle("So sánh các sản phẩm," + CategoryService.GetCategoryById(proModel.Products[0].CategoryId).Name); //todo: replaced by ngocbv
            ViewData["Title"] =
                Utilities.GetTitle("So sánh các sản phẩm," +
                                   MainService.GetInstant().CategoryService.GetCategoryById(
                                       proModel.Products[0].CategoryId).Name);
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(proModel.Products[0].CategoryId); //todo: replace by ngocbv
            ViewData["CloudData"] =
                MainService.GetInstant().CategoryService.GetCloudCategory(proModel.Products[0].CategoryId);
            return View("DisplayProductCompare", proModel);
        }

        public ActionResult SelectCompare(string ids, int pageIndex = 1)
        {
            // get ids
            var exclusiveProIds = new List<int>();
            if (!string.IsNullOrEmpty(ids))
            {
                string[] tempIds = ids.Split(new[] { '-' });
                foreach (string sid in tempIds)
                {
                    int tempId = 0;
                    if (int.TryParse(sid, out tempId)) exclusiveProIds.Add(tempId);
                }
            }

            var proModel = new UIProductModels();
            // proModel.Product = ProductService.GetProduct(exclusiveProIds[0]); //todo: replaced by ngocbv
            proModel.Product = MainService.GetInstant().ProductService.GetProductById(exclusiveProIds[0]);
            // var products = ProductService.GetOthersProduct(proModel.Product.Title, exclusiveProIds, pageIndex > 0 ? pageIndex : 1); //todo: ngocbv
            var products = MainService.GetInstant().ProductService.GetOthersProductByTitle(proModel.Product.Title, exclusiveProIds, pageIndex > 0 ? pageIndex : 1);
            if (products == null || products.Count < 1)
                // products = new PaginatedList<ProductEntity>(ProductService.GetOthersProduct(proModel.Product.CategoryId, exclusiveProIds, pageIndex > 0 ? pageIndex : 1), pageIndex, pageSize);
                products = new PaginatedList<ProductEntity>(
                    MainService.GetInstant().ProductService.GetOthersProductByCategoryId(
                    proModel.Product.CategoryId, exclusiveProIds, pageIndex > 0 ? pageIndex : 1), pageIndex, pageSize);

            proModel.Products = new PaginatedList<ProductEntity>(products, pageIndex, pageSize);
            ViewData["Title"] = Utilities.GetTitle("");
            ViewData["EnableAddProductCompare"] = true;
            return View("AddProductCompare", proModel);
        }

        public string GetToken(string token, string keyword, string id)
        {
            // var products = ProductService.GetProductsByCategoryId(int.Parse(id)); //todo: ngocbv
            var products = MainService.GetInstant().ProductService.GetProductsByCategoryId(int.Parse(id));
            ProcessParameter(token, products);

            if (string.IsNullOrWhiteSpace(token))
            {
                token = "/#";
            }
            ViewData["$Products$"] = products;
            return string.Format("/san-pham/{0}/q{1}", id, token);
        }

        //sam-pham/{id}/q/{queryValues}
        /// <summary>
        /// Show list products
        /// </summary>
        /// <param name="id"></param>
        /// <param name="queryValues"></param>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public ActionResult DisplayProducts(int id, string queryValues, string keyword = "")
        {
            InitializeViewData();
            // ViewData["Navigation"] = CategoryService.GetNavigateData(id); //todo: repalced by ngocbv
            ViewData["Navigation"] = MainService.GetInstant().CategoryService.GetNavigateData(id);
            //Get page tile.
            // ViewData["Title"] = Utilities.GetTitle(CategoryService.GetCategoryById(id).Name); //todo: replaced by ngocbv
            ViewData["Title"] = Utilities.GetTitle(MainService.GetInstant().CategoryService.GetCategoryById(id).Name);
            //get footer menu data
            // ViewData["CloudData"] = CategoryService.GetCloudCategory(id); //todo: replaced by ngocbv
            ViewData["CloudData"] = MainService.GetInstant().CategoryService.GetCloudCategory(id);
            var productModels = new UIProductModels();

            productModels.CurrentCategoryId = id;
            //get detail location foreach provider
            productModels.ProviderLocations = MainService.GetInstant().ProviderService.GetProviderAllLocations();
            //get products base on query param values.
            // var products = productModels.Products = ProductService.GetProductsByCategoryId(id); //todo: ngocbv
            var products = productModels.Products = MainService.GetInstant().ProductService.GetProductsByCategoryId(id);

            if (!string.IsNullOrWhiteSpace(queryValues))
            {
                // see, if user filter by price ranges
                productModels.IsFilterByPriceRange = queryValues.Contains("g-");
                productModels.ProductsByCategory = ProcessParameter(queryValues, products);
                // see, if user filter by provider
                productModels.IsFilterByProvider = queryValues.Contains("h-");
                if (productModels.IsFilterByProvider)
                {
                    string param = string.Empty;
                    if (!ViewData["$FilterProvider$"].ToString().Contains(queryValues))
                    {
                        param = queryValues.Replace(ViewData["$FilterProvider$"].ToString(), string.Empty);
                    }

                    if (string.IsNullOrEmpty(param))
                    {
                        ViewData["RemoveFilterParam"] = Url.RouteUrl("pagination", new { id });
                    }
                    else
                    {
                        ViewData["RemoveFilterParam"] = Url.RouteUrl("displayProducts",
                                                                     new { id, queryvalues = param });
                    }
                    productModels.SelectedProviderId = int.Parse(ViewData["$FilterProvider$"].ToString().Split('-')[1]);
                }
                if (!productModels.IsFilterByPriceRange)
                {
                    Session["MinPrice"] = productModels.FilterData.MinPrice;
                    Session["MaxPrice"] = productModels.FilterData.MaxPrice;
                }
                else
                {
                    string[] prices = ViewData["$FilterPriceRange$"].ToString().Split('-');

                    productModels.SelectedMinPrice = (int.Parse(prices[1]) / 1000);
                    productModels.SelectedMaxPrice = (int.Parse(prices[2]) / 1000);
                    productModels.OldMinPrice = (int)Session["MinPrice"];
                    productModels.OldMaxPrice = (int)Session["MaxPrice"];
                }

                string pagination = string.Empty;
                if (ViewData["$Pagination$"] != null)
                {
                    pagination = ViewData["$Pagination$"].ToString();
                }
                queryValues = "/" + queryValues;
                ViewData["QueryValue"] = (pagination == string.Empty)
                                             ? queryValues
                                             : queryValues.Replace(pagination, string.Empty);
            }
            else
            {
                productModels.ProductsByCategory = new PaginatedList<ProductEntity>(products, 1, pageSize);
                Session["MinPrice"] = productModels.FilterData.MinPrice;
                Session["MaxPrice"] = productModels.FilterData.MaxPrice;
            }

            return View("ProductsGrid", productModels);
        }

        private void InitializeViewData()
        {
            //set style
            ViewData["$ChkPriceClass$"] = ViewData["$ChkPromoClass$"] = "NFCheck";
            ViewData["QueryValue"] = string.Empty;
            if (ViewData["$FilterPriceRange$"] == null)
            {
                ViewData["$FilterPriceRange$"] = string.Empty;
            }
            if (ViewData["$FilterProvider$"] == null)
            {
                ViewData["$FilterProvider$"] = string.Empty;
            }
            if (ViewData["$Sortby$"] == null)
            {
                ViewData["$Sortby$"] = string.Empty;
            }
            if (ViewData["$FilterPromotion$"] == null)
            {
                ViewData["$FilterPromotion$"] = string.Empty;
            }
            if (ViewData["$FilterPriceChange$"] == null)
            {
                ViewData["$FilterPriceChange$"] = string.Empty;
            }
            if (ViewData["$Pagination$"] == null)
            {
                ViewData["$Pagination$"] = string.Empty;
            }
            //create default order by data
            ViewData["OrderByData"] = CreateOrderByData();
        }

        private PaginatedList<ProductEntity> ProcessParameter(string paramValue, List<ProductEntity> products)
        {
            int pageIndex = 1;
            const char coma = '/';

            if (string.IsNullOrWhiteSpace(paramValue))
            {
                return new PaginatedList<ProductEntity>(products, pageIndex, pageSize);
            }
            string[] vals = paramValue.Split(coma);
            if (vals.Length > 0)
            {
                foreach (string val in vals)
                {
                    if (string.IsNullOrWhiteSpace(val))
                    {
                        continue;
                    }
                    //1. Filter by Price Change
                    if (ActionType.PriceChange.Equals(val, StringComparison.OrdinalIgnoreCase))
                    {
                        ViewData["$ChkPriceClass$"] = "NFCheck NFh";
                        ViewData["$FilterPriceChange$"] = coma + val;
                        products = products.Where(item => item.LastPrice < item.Price).ToList();
                    }
                    //2. Filter by promotion
                    else if (ActionType.Promotion.Equals(val, StringComparison.OrdinalIgnoreCase))
                    {
                        ViewData["$ChkPromoClass$"] = "NFCheck NFh";
                        ViewData["$FilterPromotion$"] = coma + val;
                        products = products.Where(item => item.Promotion != string.Empty).ToList();
                    }
                    else
                    {
                        string paramType = val.Substring(0, 1);
                        switch (paramType)
                        {
                            case ActionType.Ordered:
                                ViewData["$Sortby$"] = coma + val;
                                int orderValue = int.Parse(val.Substring(2));
                                if (orderValue == 2) //sort by price desc
                                {
                                    products = products.OrderByDescending(item => item.LastPrice).ToList();
                                }
                                else if (orderValue == 1) //sort by price asc
                                {
                                    products = products.OrderBy(item => item.LastPrice).ToList();
                                }
                                else if (orderValue == 3) //sort by last update product
                                {
                                    products = products.OrderByDescending(item => item.CreateDate).ToList();
                                }
                                ViewData["OrderByData"] = CreateOrderByData(orderValue.ToString());
                                break;
                            case ActionType.Paginated:
                                ViewData["$Pagination$"] = coma + val;
                                int.TryParse(val.Split('-')[1], out pageIndex);
                                break;
                            case ActionType.PriceRange: //filter by prices range.
                                ViewData["$FilterPriceRange$"] = coma + val;
                                string[] priceRanges = val.Split('-');
                                double minPrice = 0;
                                if (double.TryParse(priceRanges[1], out minPrice))
                                {
                                    products = products.Where(item => (item.LastPrice >= minPrice)).ToList();
                                }
                                if (priceRanges.Length > 2 && priceRanges[2] != string.Empty)
                                {
                                    double maxPrice = 0;
                                    if (double.TryParse(priceRanges[2], out maxPrice))
                                    {
                                        products = products.Where(item => (item.LastPrice <= maxPrice)).ToList();
                                    }
                                }
                                break;
                            case ActionType.Provider: //filter by 'Cua hang' provider
                                ViewData["$FilterProvider$"] = coma + val;
                                string[] pros = val.Split('-');
                                if (pros.Length > 1)
                                {
                                    int proId = 0;
                                    if (int.TryParse(pros[1], out proId))
                                    {
                                        products = products.Where(item => (item.ProviderId == proId)).ToList();
                                    }
                                }
                                break;
                        }
                    } //end of filter data base on paramester
                }
            }
            return new PaginatedList<ProductEntity>(products, pageIndex, pageSize);
        }

        private string GetWebContent(string link)
        {
            string content = string.Empty;

            try
            {
                var httpRequest = WebRequest.Create(link) as HttpWebRequest;
                var httpResponse = httpRequest.GetResponse() as HttpWebResponse;

                using (var reader = new StreamReader(httpResponse.GetResponseStream()))
                {
                    content = reader.ReadToEnd();
                    reader.Close();
                }
            }
            catch
            {
            }

            return content;
        }

        private List<SelectListItem> CreateOrderByData(string selectedValue = "0")
        {
            var result = new List<SelectListItem>();

            result.Add(new SelectListItem
                           {
                               Text = "Độ liên quan",
                               Value = "0",
                               Selected = "0".Equals(selectedValue)
                           });

            result.Add(new SelectListItem
                           {
                               Text = "Giá tăng dần",
                               Value = "1",
                               Selected = "1".Equals(selectedValue)
                           });

            result.Add(new SelectListItem
                           {
                               Text = "Giá giảm dần",
                               Value = "2",
                               Selected = "2".Equals(selectedValue)
                           });

            result.Add(new SelectListItem
                           {
                               Text = "Sản phẩm mới cập nhật",
                               Value = "3",
                               Selected = "3".Equals(selectedValue)
                           });
            return result;
        }

        #region Nested type: ActionType

        public struct ActionType
        {
            public const string Paginated = "p";
            public const string Ordered = "o";
            public const string Promotion = "khuyen-mai";
            public const string PriceChange = "giam-gia";
            public const string City = "t";
            public const string PriceRange = "g";
            public const string Provider = "h";
        }

        #endregion
    }
}